import com.bourre.core.HashCodeFactory;
import com.bourre.utils.ClassUtils;

import fever.utils.ASType;


/**
 * @author Romain Ecarnot
 */
class fever.utils.TypeUtils
{
	/**
	 * Returns {@code true} if the passed-in {@code object} is an instance 
	 * of passed-in {@code type} type.
	 * 
	 * @param object The object to check
	 * @param type The type to check
	 * @return {@code true} if {@code object} is an instance of {@code type}
	 */
	public static function isInstanceOf( object, type : Function ) : Boolean
	{
		return ( type === Object ) ? true : object instanceof type;
	}
	
	/**
	 * 
	 * <p>A super class must be in prototype chain of sub class.
	 */
	public static function isSubClassOf( object , superClass : Function ) : Boolean
	{
		return ClassUtils.inheritsFromClass( object, superClass );
	}
	
	/**
	 * 
	 * <p>A super class must be in prototype chain of sub class.
	 */
	public static function isImplementationOf( object , interfaze : Function ) : Boolean
	{
		if( isSubClassOf( object, interfaze ) ) return false;
		else
		{
			if( typeof( object )== 'function' ) object = buildBasicInstance( object );	
			return ( object instanceof interfaze );
		}
		return false;
	}
	
	/**
	 * Creates a basic instance of passed-in {@code type}.
	 * 
	 * <p>Constructor is not call.
	 * 
	 * @param type Instance type to create
	 * @return New instance of type {@code type}
	 */
	public static function buildBasicInstance( type : Function ) : Object
	{
		var o : Object = new Object();
		o.__proto__ = type.prototype; 
		o.__constructor__ = type;
		return o;
	}
	
	/**
	 * Builds and returns new instance defined by passed-in {@code namespace} class 
	 * namespace and {@code args} constructor arguments.
	 * 
	 * @return new {@code namespace} instance 
	 */
	public static function buildInstance( namespace : String, args : Array )
	{
		return HashCodeFactory.buildInstance( namespace, args );
	}
	
	/**
	 * Checks if the type of the passed-in {@code object} matches the passed-in 
	 * {@code type}.
	 * 
	 * <p>Every value (even {@code null} and {@code undefined}) matches type
	 * {@code Object}.
	 *
	 * <p>Instances as well as their primitive correspondent match the types 
	 * {@code String}, {@code Number} or {@code Boolean}.
	 * 
	 * @param object the object whose type to compare with the passed-in {@code type}
	 * @param type the type to use for the comparison
	 * @return {@code true} if the type of the {@code object} matches the passed-in
	 * {@code type} else {@code false}
	 */
	public static function typesMatch( object, type : Function ) : Boolean
	{
		if ( type === Object ) return true;
		
		if ( isPrimitive( object ) )
		{
			var t : String = typeof( object );
			
			if( ( type === String || isSubClassOf( type, String ) ) && t == ASType.STRING )	
				return true;
			
			if( ( type === Boolean || isSubClassOf( type, Boolean ) ) && t == ASType.BOOLEAN )
				return true;
			
			if ( ( type === Number || isSubClassOf( type, Number ) ) && t == ASType.NUMBER )
				return true;
			
			return false;
		}
		else return ( isInstanceOf( object, type ) );
	}
	
	/**
	 * Returns {@code true} if the passed-in {@code object} is a primitive type.
	 * 
	 * @param object The object to check
	 * @return {@code true} if {@code object} is a primitive type else {@code false}
	 */
	public static function isPrimitive( object ) : Boolean
	{
		var t : String = typeof( object );
		return ( t == ASType.STRING || t == ASType.NUMBER || t == ASType.BOOLEAN );
	}
	
	public static function isTypeOf( object, type : String ) :Boolean
	{
		return typeof( object ) == type;
	}
}